#include	"a_global_vars.h"
#include	"config_parser.h"
#include	"str_parser.h"

//---------------------------------------STRUCTS--------------------------------------------------
struct server_info_t {

	node_id_t server_id;
	char ip[16];
	int port;

	int self_sid;
	int successor_sid;

	int multicast_recv_sid;
	int multicast_send_sid;

	int learner_tcp_sid;
	int proposer_udp_id; // only for the multicast sender.
};
//-------------------------------------------------------------
struct proxy_info_t {

	node_id_t proxy_id;
	char ip[16];
	int port;
	int proxy_sid;

};
//-------------------------------------------------------------
struct learner_acceptor_t {

	node_id_t learner_id;
	node_id_t acceptor_id;
	int acceptor_port;

};
//-------------------------------------------------------------
struct config_info_t {

	node_id_t self_id;

	int total_num_acceptors;
	int total_num_proxies;
	int total_num_learners;

	char * multicast_ip;
	int multicast_port;

	server_info server_infos[MAX_SERVERS];
	proxy_info proxy_infos[MAX_PROXIES];
	learner_acceptor learner_to_acceptor[MAX_LEARNERS];

	int proposer_to_multicaster_port;
};
//---------------------------------------VARIABLE DEFINISTIONS------------------------------------
config_info *config_info_sample = NULL;
//--------------------------------------------------------------------------------------------------------------------------
config_info * get_config_info() {
	return config_info_sample;
}
//-------------------------------------------------------------
void call_ip(const char * config_path, int process_id) {
	char flag;
	char *match;
	config_info_sample = malloc(sizeof(config_info));
	assert(config_info_sample != NULL);
	config_info_sample->self_id = (node_id_t) process_id;

	match = "acceptor";
	flag = 'a';
	get_ip_port(config_path, get_config_info(), match, flag);

	match = "proxy";
	flag = 'p';
	get_ip_port(config_path, get_config_info(), match, flag);

	match = "learner_to_acceptor";
	flag = 'l';
	get_ip_port(config_path, get_config_info(), match, flag);

	match = "multicast";
	char multicast_ip[STRING_SIZE];
	get_multicast_address(config_path, multicast_ip, match);
	config_info_sample->multicast_ip = multicast_ip;

	match = "proposer_to_multicaster";
	char proposer_multicaster_port[STRING_SIZE];
	get_multicast_address(config_path, proposer_multicaster_port, match);
	config_info_sample->proposer_to_multicaster_port = atoi(
			proposer_multicaster_port);

	create_sockets(config_info_sample);
	form_ring(config_info_sample);
}
//-------------------------------------------------------------
void get_ip_port(const char* config_file, config_info * config,
		const char * match, char flag) {

	FILE * fp;
	char line[STRING_SIZE];
	char word[STRING_SIZE];
	int last_index = -1, server_counter = 0;

	fp = fopen(config_file, "r");
	while (!feof(fp)) {
		if (fgets(line, STRING_SIZE, fp) != 0) {
			last_index = get_substr(0, strlen(line) - 1, line, word);

			if (strcmp(word, match) == 0) {

				last_index = get_substr(last_index + 1, strlen(line) - 1, line,
						word);
				if (flag == 'a')
					config->server_infos[server_counter].server_id
							= (node_id_t) atoi(word);
				else if (flag == 'p')
					config->proxy_infos[server_counter].proxy_id
							= (node_id_t) atoi(word);
				else if (flag == 'l')
					config->learner_to_acceptor[server_counter].learner_id
							= (node_id_t) atoi(word);

				last_index = get_substr(last_index + 1, strlen(line) - 1, line,
						word);
				if (flag == 'a')
					memcpy(config->server_infos[server_counter].ip, word,
							strlen(word));
				else if (flag == 'p')
					memcpy(config->proxy_infos[server_counter].ip, word,
							strlen(word));
				else if (flag == 'l')
					config->learner_to_acceptor[server_counter].acceptor_id
							= (node_id_t) atoi(word);

				last_index = get_substr(last_index + 1, strlen(line) - 1, line,
						word);
				if (flag == 'a')
					config->server_infos[server_counter].port = atoi(word);
				else if (flag == 'p')
					config->proxy_infos[server_counter].port = atoi(word);
				else if (flag == 'l')
					config->learner_to_acceptor[server_counter].acceptor_port
							= atoi(word);

				server_counter++;
			}
		}
	}
	if (flag == 'a')
		config->total_num_acceptors = server_counter;
	else if (flag == 'p')
		config->total_num_proxies = server_counter;
	else if (flag == 'l')
		config->total_num_learners = server_counter;
}
//-------------------------------------------------------------
void get_multicast_address(const char* config_file, char *ip,
		const char * match) {

	FILE * fp;
	char line[STRING_SIZE], word[STRING_SIZE];
	int last_index = -1;

	fp = fopen(config_file, "r");
	while (!feof(fp)) {
		if (fgets(line, STRING_SIZE, fp) != 0) {
			last_index = get_substr(0, strlen(line) - 1, line, word);
			if (strcmp(word, match) == 0)
				last_index = get_substr(last_index + 1, strlen(line) - 1, line,
						ip);
		}
	}
}
//-------------------------------------------------------------
void form_ring(config_info *config) {

	if (config->server_infos[config->self_id].self_sid
			!= config->total_num_acceptors - 1) {
		config->server_infos[config->self_id].self_sid = UDP_server(
				config->server_infos[config->self_id].ip,
				config->server_infos[config->self_id].port);
		config->server_infos[config->self_id].successor_sid = UDP_client(
				config->server_infos[config->self_id + 1].ip,
				config->server_infos[config->self_id + 1].port);
	} else {
		config->server_infos[config->self_id].self_sid = UDP_server(
				config->server_infos[config->self_id].ip,
				config->server_infos[config->self_id].port);
		config->server_infos[config->self_id].successor_sid = UDP_client(
				config->server_infos[0].ip, config->server_infos[0].port);
	}

}
//-------------------------------------------------------------
void create_sockets(config_info *config) {
	if (config->self_id == 0) {
		config->server_infos[config->self_id].multicast_send_sid
				= create_ip_multicast_sender_socket(config->multicast_ip);
	} else {
		config->server_infos[config->self_id].multicast_recv_sid
				= create_ip_multicast_receiver_socket(config->multicast_port,
						config->multicast_ip,
						config->server_infos[config->self_id].ip);
	}
}
//--------getters------------
int GET_SELF_SID() {
	return config_info_sample->server_infos[config_info_sample->self_id].self_sid;
}
int GET_SUCCESSOR_SID() {
	return config_info_sample->server_infos[config_info_sample->self_id].successor_sid;
}
int GET_SID_FOR_PROPOSER() {
	return config_info_sample->server_infos[config_info_sample->self_id].proposer_udp_id;
}
int GET_SID_FOR_LEARNER() {
	return config_info_sample->server_infos[config_info_sample->self_id].learner_tcp_sid;
}
int GET_SID_FOR_MULTICAST_RECV() {
	return config_info_sample->server_infos[config_info_sample->self_id].multicast_recv_sid;
}
int GET_SID_FOR_MULTICAST_SEND() {
	return config_info_sample->server_infos[config_info_sample->self_id].multicast_send_sid;
}
struct sockaddr_in GET_MULTICAST_SOCKADDR() {
	return getAddr(config_info_sample->multicast_port,
			config_info_sample->multicast_ip);
}
